home *** CD-ROM | disk | FTP | other *** search
/ Aminet 25 / Aminet 25 (1998)(GTI - Schatztruhe)[!][Jun 1998].iso / Aminet / dev / misc / ppcpack.lha / c.txt next >
Encoding:
Text File  |  1998-04-28  |  17.2 KB  |  503 lines

  1. B) PowerPC Support in C or C++
  2. ==============================
  3.  
  4. Principially PPC Developpement in C/C++ runs in 5 phases:
  5.  
  6. 1) Rewrite all 68k ASM Stuff in C
  7. 2) Adapt Source to ANSI/StormC
  8. 3) Adapt to PPC
  9. 4) Contextswitch-Optimizing
  10. 5) Further Adaptions
  11.  
  12. Contrary to what you might believe, 3) is only a very small step,
  13. the big step is 2). And yes, you can do this already, even if you
  14. do not own a PPC, mainly. I will explain the different steps of
  15. developpement now in a more detailed way.
  16.  
  17. It has to be outlined, that it is advised to do steps 1)/2) already
  18. while developping an 68k version, even if at first no PPC Version is
  19. planned. It will simplify the PPC Developpement much, and it in fact
  20. does not need too much extra work...
  21.  
  22. It has also to be noted, that things are not that easy using the PPC
  23. Software from Phase 5. This is a special feature of the WarpOS Software,
  24. that things can be such easy.
  25.  
  26. I won't discuss rewriting 68k ASM to C Source here, you should be able
  27. to do this yourselves.
  28.  
  29. 2) Adapt Source to ANSI/StormC
  30. ------------------------------
  31.  
  32. The most work is not the adaption to PPC, but the adaption from SAS/C or
  33. GNU C to StormC. StormC is a strict ANSI compiler, because of that it
  34. knows only Standard-C-Functions that are contained in the ANSI-Standard.
  35. Some of the not-supported functions can be emulated using the not-yet-released
  36. UnixLib, though.
  37.  
  38. It should be noted, that, if your program compiles on SAS/C with the
  39. STRICT ANSI mode set. You can think of StormC as a compiler that ALWAYS
  40. runs in STRICT ANSI mode.
  41.  
  42. The following SAS/C Functions are not contained in ANSI, and thus not
  43. supported by StormC (most of them are quite exotic functions, and it is
  44. possible that you do not even know a lot of them, even if you are a proficient
  45. C Coder) :
  46.  
  47. astcsma     isascii     iscsym      iscsymf     toascii     scdir       stcpm
  48. stcpma      stcsma      stccpy      stpcpy      stcis       stcisn      stclen
  49. stpbrk      stpchr      stpchrn     strcmpi     strnset
  50. strset      stcarg      stpsym      stptok      stpblk      strbpl      strdup
  51. strins      strmid      stcd_i      stcd_l      ecvt        fcvt        gcvt
  52. stch_i      stch_l      stci_d      stci_h      stci_o      stcl_d      stcl_h
  53. stcl_o      stco_i      stco_l      stcu_d      stcul_d     toascii     stpdate
  54. stptime     __datecvt   __timecvt   utpack      utunpk      cot         iabs
  55. max         min         pow2        __emit      getreg      putreg      geta
  56. isatty      ovlyMgr     dqsort      fqsort      lqsort      sqsort      strsrt
  57. tqsort      drand48     erand48     jrand8      lcong48     lrand48     mrand8
  58. nrand48     seed48      srand48     __autoopenfail          chkabort    Chk_Abort
  59. _CXBRK      __exit      onexit      _XCEXIT     forkl       forkv       onbreak
  60. wait        waitm       bldmem      rstmem      sizmem      chkml       getmem
  61. getml       halloc      lsbrk       sbrk        _MemCleanup rbrk        rlsmem
  62. rlsml       memccpy     movmem      repmem      setmem      swmem       except
  63. __matherr   poserr      datecmp     timer       __tzset     getch       fgetchar
  64. fputchar    _dread      _dwrite     read        write       clrerr      close
  65. _dclose     fcloseall   creat       _dcreat     _dcreatx    fdopen      fileno
  66. fmode       iomode      open        _dopen      flushall    mkstemp     mktemp
  67. setnbf      _dseek      lseek       tell        access      chkufb      chmod
  68. fstat       getfa       getft       stat        stcgfe      stcgfn      stcgfp
  69. strmfe      strmfn      strmfp      strsfn      unlink      argopt      chgclk
  70. dos_packet  getclk      getasn      getdfs      putenv      rawcon      stackavail
  71. stacksize   stackused   chdir       closedir    dfind       dnext       findpath
  72. getcd       getcwd      getfnl      getpath     mkdir       opendir     readdir
  73. rmdir       seekdir     rewinddir   telldir     readlocale  scr_beep    scr_bs
  74. scr_cdelete scr_cinsert scr_clear   scr_cr      scr_curs    scr_cursrt  scr_cursup
  75. scr_eol     scl_home    scr_ldelete scr_lf      scr_linsert scr_tab     _CXFERR
  76. _CXOVF      _EPILOG     _PROLOG
  77.  
  78. The most important of the "not allowed" functions are the Level 0 I/O functions
  79. (open,close,read,write). Use fopen,fclose,fread,fwrite instead.
  80.  
  81. Note: Some of these functions might be included, in the first version of this text
  82. i by mistake declared stricmp and strnicmp as not included (what is wrong), there
  83. might be more errors in the list :) But probably not many... probably none...
  84.  
  85. But STRICT ANSI does not only limit the functions, there are also some things,
  86. that cause a warning from SAS/C, but an error from a strict ANSI Compiler.
  87.  
  88. Things like:
  89.  
  90. char *string=malloc(300);
  91.  
  92. cause an error from StormC. Correct would be:
  93.  
  94. char *string=(char *)malloc(300);
  95.  
  96. ANSI wants STRONG TYPING. If you do not own StormC, but want to make your code
  97. as easy compilable with StormC PPC later, compile with STRICT ANSI. Problems
  98. appear especially with function pointers. If you are not sure how to cast
  99. a thing for STRICT ANSI, maybe you should try void *, it works often for
  100. not strongly typed source.
  101.  
  102. You should also replace all K&R Syntax (example)
  103.  
  104. void main(argv,argc)
  105. int argv;
  106. char **argc;
  107.  
  108. by the normal syntax (example)
  109.  
  110. void main(int argv,char **argc);
  111.  
  112. Also a code like
  113.  
  114. int a=5;
  115. int stuff[a];
  116.  
  117. is not legal on ANSI. Array Dimensions have to be constants.
  118. If you need them variable, use dynamic allocation using malloc.
  119.  
  120. A good method to convert to "Strict ANSI" is the following:
  121.  
  122. 1. Just compile it, and look at every warning and error
  123. 2. Typecast everything that looks like a pointer (and causes
  124.    an error) to void *, everything else that causes problems,
  125.    to a int, long or double.
  126. 3. If some things still don't work, have a look at them now.
  127.  
  128. Some Sources (like the Source of Doom) require parts of the
  129. Unix/TCP includes. If you need such things, please contact me,
  130. i have converted the needed things to StormC (contact address
  131. see below).
  132.  
  133. Now we are nearly done with the ANSI/StormC Adaption. At the end
  134. some keyword have to be defined differently:
  135.  
  136. #define __stdargs
  137. #define __regargs
  138. #define __asm
  139. #define __far FAR
  140. #define __inline inline
  141. #define __volatile volatile
  142.  
  143. __chip, __fast and __interrupt do not exist on StormC, they have to
  144. be replaced by the appropriate OS Functions. Some programmers also
  145. use some strange cominations that won't work (static inline is complete
  146. nonsese, get it Unix-coders :) !!! Static OR inline but not both of them !!!)
  147.  
  148. And if we are at "bad coding style": Bitfields only exist on C++, not
  149. in ANSI C...
  150.  
  151. Ah, and one word to those fclose-always-works-fans. No, fclose does
  152. not work, if the file is NOT OPEN !!! You crash your task, if you try
  153. to close a file, that is not open.
  154.  
  155. Do
  156.  
  157. if (file) fclose(file);
  158.  
  159. Some words to __attribute__ ((packed)). It does not exist, and is a
  160. feature that would slow down the PPC *much*, if it would exist. Please
  161. do not use __attribute ((packed)). The PPC needs a certain alignment
  162. to get optimal speed.
  163.  
  164. About Text Constants longer than a line:
  165.  
  166. It is legal to write:
  167.  
  168. char *bla="...."\
  169.           "...."\
  170.           "....";
  171.  
  172. But the last character before the \ should be a \ here.
  173.  
  174. The notation
  175.  
  176. char bla[]={"..."\
  177.             "..."};
  178.  
  179. is not legal (This is sometimes used in GNU C Sources).
  180.  
  181. If you have done all this, you now (should) have a working StormC 68k Source.
  182. Now we go to the PPC stuff. The most work is done now. Only small things
  183. remain to do. PPC-handling is mostly done internal by the compiler.
  184.  
  185. C. Adapt to PPC
  186. ---------------
  187.  
  188. At first we have to change register parameters:
  189.  
  190. void test(register __a0 mytest);
  191.  
  192. has to be changed (for example) to
  193.  
  194. void test(register mytest);
  195.  
  196. The PPC does not know a register a0. But you can tell him to use a
  197. register by usage of the keyword "register", without specifying a
  198. register number.
  199.  
  200. Next we have to do some changes to OS-Includes:
  201.  
  202. up to now, depending on which compiler you used, you did (example):
  203.  
  204. #include <clib/exec_protos.h>
  205. #include <pragmas/exec_pragmas.h>
  206.  
  207. or
  208.  
  209. #include <clib/exec_protos.h>
  210. #include <pragma/exec_lib.h>
  211.  
  212. or
  213.  
  214. #include <clib/exec_protos.h>
  215. #include <inline/exec.h>
  216.  
  217. or
  218.  
  219. #include <proto/exec.h>
  220.  
  221. For StormC PPC you do:
  222.  
  223. #include <clib/exec_protos.h>
  224.  
  225. Do not include any pragmas/pragma files, or you will be swamped by error-messages.
  226. Also do not include any proto/ files.
  227.  
  228. If you want to compile your source for both 68k and PPC (without changing the
  229. source) you do:
  230.  
  231. #include <clib/exec_protos.h>
  232. #ifndef __PPC__
  233. #include <pragma/exec_lib.h>
  234. #endif
  235.  
  236. __PPC__ is always set correctly.
  237.  
  238. Yet another difference between 68k and PPC concerns the usage of Subtasks. If you
  239. want to do the Subtask as PPC Task (recommended) you have to replace functions like
  240. CreateTask() by CreateTaskPPC() of the powerpc.library. I won't go into detail here,
  241. most of the time the API is absolutely identic to the usual functions, with the
  242. exception of a PPC at the end of the function name. Read the documentation of
  243. WarpOS for more information.
  244.  
  245. The other method would be doing the subtask as 68k task and calling CreateTask().
  246. To do so you would have to make your program a mixed Binary, though, and you also
  247. would not get full PPC Speedup. So usually (unless the subtask does many OS Calls)
  248. the CreateTaskPPC() approach is the better method. Also, it is recommended not to
  249. use 68k Subtasks in PPC programs, so that your program will get optimal speed
  250. on a 100% PPC Amiga System (that surely will appear some time in the future).
  251.  
  252. Earlier versions of the compiler had problems with Tags-versions of OS-functions.
  253. This is fixed since quite some time now. I did not notice, that is why i said
  254. in earlier versions of this document, that you would have to change this code.
  255. I did not test since quite some time.
  256.  
  257. Then we come to the BeginIO-Function. This function only exists with a
  258. Library Base on the PPC Compiler. You can use the following code (example
  259. is for audio.device):
  260.  
  261. #include <libraries/powerpc.h>
  262. #include <ppcamiga.h>
  263.  
  264. void BeginIOAudioPPC(struct IORequest *arg1)
  265. {
  266.         extern struct Library *AudioBase;
  267.         ULONG regs[16];
  268.         regs[9] = (ULONG) arg1;
  269.         __CallLibrary(AudioBase,-30,regs);
  270. }
  271.  
  272. An example how this can be used (out of the Sound-Code of ZhaDoom...):
  273.  
  274.   AudioBase = (struct Library *)audio_io->ioa_Request.io_Device;
  275.   c = &channel_info[cnum];
  276.   c->audio_io->ioa_Request.io_Command = CMD_WRITE;
  277.   c->audio_io->ioa_Request.io_Flags = ADIOF_PERVOL;
  278.   c->audio_io->ioa_Data = &chip_cache_info[cache_chip_data (id)].chip_data[8];
  279.   c->audio_io->ioa_Length = lengths[id] - 8;
  280.   c->audio_io->ioa_Period = period_table[pitch];
  281.   c->audio_io->ioa_Volume = vol << 2;
  282.   c->audio_io->ioa_Cycles = 1;
  283. #ifdef __PPC__
  284.   BeginIOAudioPPC((struct IORequest *)c->audio_io);
  285. #else
  286.   BeginIO ((struct IORequest *)c->audio_io);
  287. #endif
  288.  
  289. You see? You always have to read out the LibraryBase of a device to do
  290. a BeginIO on PPC...
  291.  
  292. Some readers now probably ask themselves what about the famous
  293. "Context-Switch". Well, the truth is, under StormC, the Compiler
  294. automatically deals with the Contextswitch. You won't have to think
  295. about it... i will lose some words about it anyways:
  296.  
  297. There are two sorts of Contextswitches:
  298.  
  299. a) Function-Contextswitches
  300.  
  301. You have to compile with Debugging-Information the first time you compile
  302. the Source. Then the compiler handles the Contextswitches automatically.
  303. Later you can compile without Debugging-Information, if you want.
  304.  
  305. b) Library-Contextswitches
  306.  
  307. These need so-called "function-stubs". ppcamiga.lib already contains
  308. the function-stubs for all Amiga-OS-functions, and for the 68k-functions
  309. of rtgmaster (But for rtgmaster also PPC-functions exist, and it is
  310. adviced to use these). To create a stub for a not yet supported library,
  311. you do:
  312.  
  313. genppcstub mylib_protos.h mylib.fd VERBOSE
  314.  
  315. You need the proto- and the FD-File to create the stub. The stub is a
  316. C Source file that you link together with your Source. The Contextswitch
  317. itselves then works automatically.
  318.  
  319. D.) Contextswitch-Optimizing
  320. ----------------------------
  321.  
  322. With WarpOS a Contextswitch needs about 0.5 milliseconds (with a 200 MHz
  323. PPC 604e Board...). It should be avoided to do "many Contextswitches
  324. per Second" (BTW: The Phase 5 Software needs about 1 millisecond for a
  325. Contextswitch).
  326.  
  327. Example of things to avoid:
  328.  
  329. - Load Files on a Byte-per-Byte basis with fgetc (use fread instead
  330.   and load to a Fastram Buffer, from which you get the stuff on a
  331.   Byte-Per-Byte-Basis then)
  332. - WritePixel (work on a Fastram-Buffer instead)
  333. - OS-Calls that are called often per second
  334.  
  335. Graphics can be handled completely PPC Native by using rtgmaster.
  336. rtgmaster is a PPC Shared Library.
  337.  
  338. Notice, that some of the Standard-C-Functions do Contextswitches.
  339. I think clock() is among them, but am not sure about it. A possibility
  340. to deal timing without Contextswitches for sure is to use the PPC
  341. timer directly, in PPC ASM:
  342.  
  343. double tb_scale_lo = ((double)(bus_clock >> 2)) / 35.0;
  344. double tb_scale_hi = (4.294967296E9 / (double)(bus_clock >> 2)) * 35.0;
  345.  
  346. bus_clock is set to the Bus Clock in Hz, for example 50000000 for
  347. a 150 MHz Board, 66000000 for a 200 MHz Board.
  348.  
  349. Stopping time is then done like this (example of the I_GetTime-function
  350. of Doom):
  351.  
  352. int I_GetTime (void)
  353. {
  354.  unsigned int clock[2];
  355.  double currtics;
  356.  static double basetics=0.0;
  357.         ppctimer (clock);
  358.  if (basetics == 0.0)
  359.   basetics = ((double) clock[0])*tb_scale_hi + ((double) clock[1])/tb_scale_lo;
  360.  currtics = ((double) clock[0])*tb_scale_hi + ((double) clock[1])/tb_scale_lo;
  361.  return (int) (currtics-basetics);
  362. }
  363.  
  364.  
  365. ppctimer looks like (object code for people who do not have StormPowerASM
  366. is contained inside this archive):
  367.  
  368.  vea
  369.  XDEF    _ppctimer
  370.  
  371. _ppctimer:      mftbu   r4
  372.                 mftbl   r5
  373.                 mftbu   r6
  374.                 cmpw    r4,r6
  375.                 bne     _ppctimer
  376.  
  377.                 stw     r4,0(r3)
  378.                 stw     r5,4(r3)
  379.                 blr
  380.  
  381. But well, as i said, i am not sure, if clock() does use Contextswitches or not.
  382. Only i had the feeling that ZhaDoom speed up, after i replaced the usage of clock()
  383. by the usage of ppctimer().
  384.  
  385. 5) Further Adaptions
  386. --------------------
  387.  
  388. Note: The following is fully optional !!! (But it might speed up some things)
  389.  
  390. It is possible to declare waste memory-areas as non-cachable using the BAT-registers
  391. of the PPC. How this is exactly done, read the documentation of WarpOS.
  392.  
  393. Another optimization would be re-writing parts of the code in PPC Assembler.
  394. As to this, see below.
  395.  
  396. In some newsgroups it was discussed to run program parts asynchronely on the
  397. 68k. Some people even claimed this would only be possible with the Phase 5
  398. software. This is not true, if you want to implement it, you would use the
  399. PPC-Native Message-System of WarpOS (keyword "AllocXMsg", refer to WarpOS
  400. documentation). But i want to outline the disadvantages of this "parallel"
  401. method:
  402.  
  403. 1) On PPC-only machines such code would have serious disadvantages. And such
  404.    systems will come...
  405. 2) The PowerUP-Hardware is not good for true Multi-Processoring. As soon as
  406.    your 68k/PPC tasks share memory, you will get serious problems. I won't get
  407.    into detail, it was discussed enough in the newsgroup. And it really is not
  408.    worth the effort.
  409.  
  410. I seriously recommend to work only "synchrone", doing Sub-Tasks only on the
  411. same CPU the mainprogram also is running on.
  412.  
  413. Sometimes it is also useful to do a manual Contextswitch to a 68k ASM function.
  414. If the ASM functions contains tons of OS calls, for example. But if you have such
  415. code, i recommend using a Mixed Binary, anyways. Makes things more easy.
  416.  
  417. PowerPC ASM Optimization
  418. ------------------------
  419.  
  420. At last this one. Again i have to say, that it makes no sense to implement
  421. the whole stuff in PPC ASM. You start like this:
  422.  
  423. 1) Implement all in C
  424. 2) Compile it for 68k and use the Profiler of StormC (the profiler currently
  425.    only exists for 68k, but its data is also useful for PPC)
  426.  
  427. When you use the profiler you run the program, and it does a statistic about
  428. which functions use how much CPU time. Then you implement the functions that
  429. take the most CPU time in PPC ASM. It is that simple.
  430.  
  431. You have to keep in mind, though:
  432.  
  433. - even ASM can't speedup massive numbers of Context-Switches
  434. - ASM also can't speed up the slow GFX Bus of the Amiga (Even Zorro III is
  435.   slow as to today's standards...)
  436.  
  437. Remember always:
  438.  
  439. Doing a fast implementation in C and then using a Profiler to find out which
  440. functions are worth a ASM Optimization is much more clever than doing everything
  441. in PPC ASM.
  442.  
  443. Of course the profiler is only available, if you own StormC. SAS/C and GNU C
  444. do not have a profiler.
  445.  
  446. Now, what do you do, if your "original" source is in ASM, not in C ? Well,
  447. you insert timing checks and write some timing data to a file ("manual
  448. Profiling") at places where you think the most time is wasted. Of course,
  449. real profiling (using StormC) is much more easy. Also remember, that C
  450. defines it's functions like:
  451.  
  452. _Functionname
  453.  
  454. So if you want to profile ASM-Stuff you have to add a leading _ to all functionnames,
  455. and to XDEF them all.
  456.  
  457. Example:
  458.  
  459. stuff.asm
  460. ---------
  461.  
  462. start:
  463.  
  464. jsr morestuff
  465. ; lots of code
  466.  
  467. rts
  468. ; lots of functions
  469. morestuff:
  470. ; lots of code
  471. rts
  472.  
  473. Would have to be changed to:
  474.  
  475. startit.c
  476. ---------
  477.  
  478. extern void start(void);
  479.  
  480. void main()
  481. {
  482.  start();
  483. }
  484.  
  485. stuff.asm
  486. ---------
  487.  
  488.     XDEF _start
  489.     XDEF _morestuff
  490.     ;... lots of functions
  491. _start:
  492.     jsr _morestuff
  493.     ;lots of code
  494.  
  495.     rts
  496. _morestuff:
  497.     ;lots of code
  498.     rts
  499.  
  500. Well, and now you can start profiling... the C thing simply starts the ASM
  501. main function...
  502.  
  503.